﻿using NetworkPower.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Globalization;
using System.Text.RegularExpressions;
using System.IO;
using NPOI.HSSF.UserModel;
using NPOI.SS.Util;
using NPOI.HPSF;
using NPOI.SS.UserModel;
using NPOI.HSSF.Util;
using Microsoft.Win32;
using NetworkPower.DataModel.Models;

namespace NetworkPower.UI
{
    /// <summary>
    /// Interaction logic for ComparePort.xaml
    /// </summary>
    public partial class ComparePort : Window, IDisposable
    {
        static NetworkPowerContext context = new NetworkPowerContext();
        private Dictionary<Guid, string> Equipments = new Dictionary<Guid, string>();
        private Dictionary<Guid, string> Departments = new Dictionary<Guid, string>();
        private Project project = null;
        public ComparePort(Project project)
        {
            InitializeComponent();
            MatchingRule.LoadMatchingRule();
            this.project = project;
            this.txtProjectName.Text = project.ProjectName;
            BindVoltage();
        }

        private void BindVoltage()
        {
            var datasource = context.Voltages.Where(v => v.ProjectID == project.ProjectID).OrderBy(v => v.VoltageValue).ToList();
            voltageLevelLeft.ItemsSource = datasource;
            voltageLevelRight.ItemsSource = datasource;
        }

        private void LoadData()
        {
            context.Set<Equipment>().ToList().ForEach(s => Equipments.Add(s.EquipmentID, s.EquipmentName.Replace(".xls", "")));
        }

        private LoopLine[] GetSelectedRows(DataGrid datagrid)
        {
            if (datagrid != null && datagrid.SelectedCells.Count > 0)
            {
                LoopLine[] dv = new LoopLine[datagrid.SelectedCells.Count];
                for (int i = 0; i < datagrid.SelectedCells.Count; i++)
                {
                    dv[i] = datagrid.SelectedCells[i].Item as LoopLine;

                }
                return dv.Distinct().ToArray();
            }
            return null;
        }

        private void ClearPreviousMatch()
        {
            var matches = context.LoopLines.Where(s => s.IsMatched.HasValue).ToList();
            matches.ForEach(f =>
            {
                f.IsMatched = null;
                context.Set<LoopLine>().Attach(f);
                context.Entry(f).State = System.Data.Entity.EntityState.Modified;
            });
            context.SaveChanges();
        }

        public void LoadRightLoopLine()
        {
            var selectedEquipment = EquipNameRight.SelectedItems[0] as Equipment;
            var datasource = context.LoopLines.Where(l => l.EquipmentId == selectedEquipment.EquipmentID).OrderBy(o => o.RowIndex).ToList();
            dataGridViewRight.ItemsSource = null;
            dataGridViewRight.ItemsSource = datasource;
        }

        public void LoadLeftLoopLine()
        {
            var selectedEquipment = EquipNameLeft.SelectedItems[0] as Equipment;
            var datasource = context.LoopLines.Where(l => l.EquipmentId == selectedEquipment.EquipmentID).OrderBy(o => o.RowIndex).ToList();
            dataGridViewLeft.ItemsSource = null;
            dataGridViewLeft.ItemsSource = datasource;
        }

        private void Match_Click(object sender, RoutedEventArgs e)
        {
            ClearPreviousMatch();//IsMatch为空，背景色为白色
            LoopLine[] left = GetSelectedRows(dataGridViewLeft); //获取左边选中项
            LoopLine[] right = GetSelectedRows(dataGridViewRight);//获取右边选中项
            if (left == null || right == null)
            {
                MessageBox.Show("请选择要匹配的设备。");
                return;
            }
            DeleteCableLine();//删除已匹配的项目
            SaveMatchedLinesAndUpdateLoopLine(left, right); // 保存匹配项信息,并且更新Loopline里面的isMatch
            UpdateNoMatchedLoopLine(left, right); //将未匹配的项中isMatch设置为false，用于标识它们没有匹配上，而为参加匹配的项，会继续保持isMatch = null
            SaveElectricCable();
            LoadLeftLoopLine(); //  重新加载左边的loopline，用以显示已匹配的项目的颜色，并且会把上次选中的行颜色重置为白色
            LoadRightLoopLine();//  重新加载右的loopline，用以显示已匹配的项目的颜色，并且会把上次选中的行颜色重置为白色
        }

        public void SaveMatchedLine(MatchedLine matchLine)
        {
            if (context.MatchedLines.Any(c => c.CircuitNo == matchLine.CircuitNo))
            {
                return;
            }
            else
            {
                context.Entry<MatchedLine>(matchLine).State = System.Data.Entity.EntityState.Added;
                context.SaveChanges();
            }
        }

        private void UpdateNoMatchedLoopLine(LoopLine[] left, LoopLine[] right)
        {
            for (int i = 0; i < left.Count(); i++)
            {
                var leftone = left[i];
                if (!leftone.IsMatched.HasValue)
                {
                    leftone.IsMatched = false;
                    context.Set<LoopLine>().Attach(leftone);
                    context.Entry(leftone).State = System.Data.Entity.EntityState.Modified;
                    context.SaveChanges();
                }
            }

            for (int j = 0; j < right.Count(); j++)
            {
                var rightone = right[j];
                if (!rightone.IsMatched.HasValue)
                {
                    rightone.IsMatched = false;
                    context.Set<LoopLine>().Attach(rightone);
                    context.Entry(rightone).State = System.Data.Entity.EntityState.Modified;
                    context.SaveChanges();
                }
            }
        }

        private void SaveMatchedLinesAndUpdateLoopLine(LoopLine[] left, LoopLine[] right)
        {
            if (left == null || right == null)
                return;
            for (int i = 0; i < left.Count(); i++)
            {
                right.Select(s => !string.IsNullOrWhiteSpace(s.CircuitNo) && !string.IsNullOrWhiteSpace(s.CircuitNo) && s.CircuitNo == s.CircuitNo).FirstOrDefault();
                for (int j = 0; j < right.Count(); j++)
                {
                    var leftone = left[i];
                    var rightone = right[j];
                    if (!string.IsNullOrWhiteSpace(leftone.CircuitNo) && !string.IsNullOrWhiteSpace(rightone.CircuitNo) && leftone.CircuitNo == rightone.CircuitNo)
                    {
                        var rule = MatchingRule.Rules.Where(r => r.ContentType.Contains(leftone.CircuitNo)).FirstOrDefault();
                        if (rule != null)
                        {
                            UpdateMatchedLoopLine(leftone, rightone, rule.RuleTypeId);
                            MatchedLine cableLine = new MatchedLine() { RuleTypeId = rule.RuleTypeId, CircuitNo = leftone.CircuitNo, MathchedLineId = Guid.NewGuid(), StartLoopLineId = leftone.LoopLineId, EndLoopLineId = rightone.LoopLineId };
                            SaveMatchedLine(cableLine);
                        }
                    }
                }
            }
        }

        public void DeleteCableLine()
        {
            context.MatchedLines.RemoveRange(context.MatchedLines);
            context.SaveChanges();
        }

        public void UpdateMatchedLoopLine(LoopLine leftone, LoopLine rightone, Guid ruleTypeId)
        {
            leftone.IsMatched = true;
            leftone.RuleTypeId = ruleTypeId;
            rightone.IsMatched = true;
            rightone.RuleTypeId = ruleTypeId;

            context.Set<LoopLine>().Attach(leftone);
            context.Entry(leftone).State = System.Data.Entity.EntityState.Modified;
            context.Set<LoopLine>().Attach(rightone);
            context.Entry(rightone).State = System.Data.Entity.EntityState.Modified;

            context.SaveChanges();
        }

        private void CableType_Click(object sender, RoutedEventArgs e)
        {
            string result = string.Empty;
            IEnumerable<IGrouping<Guid, MatchedLine>> query = context.MatchedLines.ToList().GroupBy(g => g.RuleTypeId, g => g);
            foreach (IGrouping<Guid, MatchedLine> info in query)
            {
                List<MatchedLine> sl = info.ToList<MatchedLine>();
                result += Utilities.GetCableType(sl.Select(s => s).FirstOrDefault().CircuitNo, sl.Count()) + "\r\n";
            }
            MessageBox.Show(result);
        }

        private void SeperatorNameLeft_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (SeperatorNameLeft.SelectedItems.Count == 1)
            {
                var selctedSeperatorType = SeperatorNameLeft.SelectedItems[0] as SeperatorType;
                var datasouce = context.Equipments.Where(eq => eq.SeperatorTypeId == selctedSeperatorType.SeperatorTypeID).ToList();
                EquipNameLeft.ItemsSource = datasouce;
            }
            else
            {
                EquipNameLeft.ItemsSource = null;
            }
        }

        private void voltageLevelLeft_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (voltageLevelLeft.SelectedItems.Count == 1)
            {
                var selectedVoltage = voltageLevelLeft.SelectedItems[0] as Voltage;
                var datasource = context.SeperatorTypes.Where(s => s.VoltageID == selectedVoltage.VoltageID).OrderBy(s => s.SeperatorValue).ToList();
                SeperatorNameLeft.ItemsSource = datasource;
            }
            else
            {
                SeperatorNameLeft.ItemsSource = null;
            }
        }

        private void EquipNameLeft_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (EquipNameLeft.SelectedItems.Count == 1)
            {
                LoadLeftLoopLine();
            }
            else
            {
                dataGridViewLeft.ItemsSource = null;
            }
        }

        private void voltageLevelRight_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (voltageLevelRight.SelectedItems.Count == 1)
            {
                var selectedVoltage = voltageLevelRight.SelectedItems[0] as Voltage;
                var datasource = context.SeperatorTypes.Where(s => s.VoltageID == selectedVoltage.VoltageID).OrderBy(s => s.SeperatorValue).ToList();
                SeperatorNameRight.ItemsSource = datasource;
            }
            else
            {
                SeperatorNameRight.ItemsSource = null;
            }
        }

        private void SeperatorNameRight_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (SeperatorNameRight.SelectedItems.Count == 1)
            {
                var selctedSeperatorType = SeperatorNameRight.SelectedItems[0] as SeperatorType;
                var datasouce = context.Equipments.Where(eq => eq.SeperatorTypeId == selctedSeperatorType.SeperatorTypeID).ToList();
                EquipNameRight.ItemsSource = datasouce;
            }
            else
            {
                EquipNameRight.ItemsSource = null;
            }
        }

        private void EquipNameRight_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (EquipNameRight.SelectedItems.Count == 1)
            {
                LoadRightLoopLine();
            }
            else
            {
                dataGridViewRight.ItemsSource = null;
            }
        }

        public string ComputeCableNumber(string equipmentName, string circuitNo)
        {
            string result = string.Empty;

            if (MatchingRule.EquipmentTypeNumberRules.Count() > 0)
            {

                //foreach (var r in MatchingRule.EquipmentTypeNumberRules)
                //{
                //    if (r.Value.IndexOf(equipmentName, 0) > 0)
                //    {
                //        MessageBox.Show("Bingo");
                //    }
                //}
                var type = MatchingRule.EquipmentTypeNumberRules.Where(v => v.Value.IndexOf(equipmentName) >= 0).FirstOrDefault();
                var equipment = context.MaxEquipmentNumbers.Where(t => t.EquipmentType == type.Key.ToString()).FirstOrDefault();
                //var code1 = MatchingRule.EquipmentTypeNumberRules.Count(o => o.Value.IndexOf(equipmentName, 0) >= 0);
                if (equipment != null)
                {
                    if (string.IsNullOrEmpty(equipment.MaxNumber))
                    {
                        result = "1";
                    }
                    else
                    {
                        string lastCharOrNumber = equipment.MaxNumber.Substring(equipment.MaxNumber.Length - 1, 1);
                        if (isCharExists(lastCharOrNumber)) //如果是含有字母的比如A-F，这种需要把最后一位变了
                        {
                            char lastChar = GetLastCharOfNumber(lastCharOrNumber);
                            char lastCharOfNextOne = (char)(lastChar + 1);
                            result = equipment.MaxNumber.Substring(0, equipment.MaxNumber.Length - 1) + lastCharOfNextOne;
                        }
                        else
                        {
                            result = (Convert.ToInt32(equipment.MaxNumber) + 1).ToString();
                        }
                    }
                }
                else //这种类型的编号还没有开始使用，所以取最小的那个
                {
                    result = Utilities.GetMixNumberByEquipmentType(equipmentName, circuitNo);
                }
            }
            return result;
        }

        public bool isCharExists(string str)
        {
            return Regex.Matches(str, "[a-zA-Z]").Count > 0;
        }

        public char GetLastCharOfNumber(string str)
        {
            char[] charlist = str.ToArray();
            return charlist[charlist.Length - 1];
        }

        private void CreateSerialNumber_Click(object sender, RoutedEventArgs e)
        {
            var preview = new PreviewReport();
            preview.ShowDialog();
        }

        private string SaveEquipmentMaxNo(string equipmentName, string circuitNo)
        {
            var type = MatchingRule.EquipmentTypeNumberRules.Where(v => v.Value.Contains(equipmentName)).FirstOrDefault();//通过选择的设备名字，查到它的类型，即就是找到了一条规则
            MaxEquipmentNumber number = null;
            number = context.MaxEquipmentNumbers.Where(s => s.EquipmentType == type.Key.ToString()).FirstOrDefault(); //通过这条规则，查找这个规则下最大的排序
            if (number != null) //如果不存在，也表示为第一次
            {
                number.MaxNumber = ComputeCableNumber(equipmentName, circuitNo); //获取最大的号码
                context.MaxEquipmentNumbers.Attach(number);
                context.Entry(number).State = System.Data.Entity.EntityState.Modified;
            }
            else
            {
                number = new MaxEquipmentNumber();
                number.MaxEquipmentNumberId = Guid.NewGuid();
                number.EquipmentType = type.Key.ToString();
                number.MaxNumber = ComputeCableNumber(equipmentName, circuitNo);
                context.MaxEquipmentNumbers.Add(number);
            }
            context.SaveChanges();
            return number.MaxNumber;
        }

        private string GetCableType()
        {
            string result = string.Empty;
            IEnumerable<IGrouping<Guid, MatchedLine>> query = context.MatchedLines.ToList().GroupBy(g => g.RuleTypeId, g => g);
            foreach (IGrouping<Guid, MatchedLine> info in query)
            {
                List<MatchedLine> sl = info.ToList<MatchedLine>();
                result += Utilities.GetCableType(sl.Select(s => s).FirstOrDefault().CircuitNo, sl.Count()) + "\r\n";
            }
            return result;
        }

        private void SaveElectricCable()
        {
            var leftEquipment = EquipNameLeft.SelectedItem as Equipment;
            var rightEquipment = EquipNameRight.SelectedItem as Equipment;
            IEnumerable<IGrouping<Guid, MatchedLine>> query = context.MatchedLines.ToList().GroupBy(g => g.RuleTypeId, g => g);
            foreach (IGrouping<Guid, MatchedLine> info in query)
            {
                List<MatchedLine> sl = info.ToList<MatchedLine>();
                var unitComposite = context.UnitComposites.Where(u => u.UnitCompositeId == leftEquipment.UnitCompositeId).FirstOrDefault();
                if (unitComposite == null)
                {
                    return;
                }
                var unitIds = unitComposite.UnitIds.Split(',');
                for (int i = 0; i < unitIds.Count(); i++)
                {
                    var MaxEquipmentNumber = SaveEquipmentMaxNo(leftEquipment.EquipmentName, sl[0].CircuitNo);
                    for (int j = 0; j < sl.Count; j++)
                    {
                        var matchedLine = sl[j];
                        var electricCable = new ElectricCable();
                        electricCable.ElectricCableId = Guid.NewGuid();
                        electricCable.UnitId = new Guid(unitIds[i]);
                        electricCable.CableNumber = MaxEquipmentNumber;
                        string cableType = Utilities.GetCableType(sl.Select(s => s).FirstOrDefault().CircuitNo, sl.Count());
                        electricCable.CableType = cableType;
                        electricCable.BackUpCoreCount = Utilities.GetNumberOfCores(sl.Count()) - sl.Count();
                        var startPoint = context.LoopLines.Where(l => l.LoopLineId == matchedLine.StartLoopLineId).FirstOrDefault();
                        if (startPoint != null)
                        {
                            electricCable.StartCircleNo = startPoint.CircuitNo;
                            electricCable.StartTerminalNo = startPoint.FullTerminalNo;
                        }
                        electricCable.StartLoopLineId = matchedLine.StartLoopLineId;
                        electricCable.Start = leftEquipment.EquipmentName;
                        var endPoint = context.LoopLines.Where(l => l.LoopLineId == matchedLine.EndLoopLineId).FirstOrDefault();
                        if (endPoint != null)
                        {
                            electricCable.EndCircleNo = endPoint.CircuitNo;
                            electricCable.EndTerminalNo = endPoint.FullTerminalNo;
                        }
                        electricCable.EndLoopLineId = matchedLine.EndLoopLineId;
                        electricCable.End = rightEquipment.EquipmentName;
                        //electricCable.LineLength = 0;
                        electricCable.Remarks = "";
                        context.ElectricCables.Add(electricCable);
                    }
                }
            }
            context.SaveChanges();
        }

        private void btnReplace_Click(object sender, RoutedEventArgs e)
        {
            ReplaceBlueprint rp = new ReplaceBlueprint(this.project);
            rp.ShowDialog();
        }

        private void btnClear_Click(object sender, RoutedEventArgs e)
        {
            MessageBoxResult result = MessageBox.Show("即将重置,系统将自动退出,请稍后重新进入程序并匹配...", "警告", MessageBoxButton.YesNo, MessageBoxImage.Question);
            if (result == MessageBoxResult.Yes)
            {
                context.Database.ExecuteSqlCommand("delete from MaxEquipmentNumbers");
                context.Database.ExecuteSqlCommand("delete from MatchedLines");
                context.Database.ExecuteSqlCommand("update LoopLines set IsMatched = null");
                context.Database.ExecuteSqlCommand("delete from ElectricCables");
                context.SaveChanges();
                System.Environment.Exit(0);
            }
            else
            {
                //
            }

            //MessageBox.Show("重置中,系统将自动退出,请稍后重新进入程序并匹配");



        }

        #region IDisposable Support
        private bool disposedValue = false; // To detect redundant calls

        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    // TODO: dispose managed state (managed objects).
                }

                // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
                // TODO: set large fields to null.

                disposedValue = true;
            }
        }

        // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
        // ~ComparePort() {
        //   // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
        //   Dispose(false);
        // }

        // This code added to correctly implement the disposable pattern.
        public void Dispose()
        {
            // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
            Dispose(true);
            // TODO: uncomment the following line if the finalizer is overridden above.
            // GC.SuppressFinalize(this);
        }
        #endregion
    }

    public class LoopLineBackColorConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value is LoopLine)
            {
                bool? isMatch = ((LoopLine)value).IsMatched;
                if (isMatch.HasValue)
                {
                    if ((bool)isMatch)
                        return Brushes.LightGreen;
                    else
                        return Brushes.DeepPink;
                }

            }
            return Brushes.White;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

}